package com.tamir.template.express.handle;

import com.tamir.template.bean.TNode;
import com.tamir.template.context.TemplateContext;
import com.tamir.template.exception.Errors;
import com.tamir.template.exception.TemplateException;
import com.tamir.template.util.ClassUtil;
import com.tamir.template.util.StringUtil;

import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author : tanggh
 * @description :〈描述〉
 * @date : 2016/10/28
 */
public abstract class AbstractExpressValueHandle implements ITExpressValueHandle
{
    protected static Pattern mapKeyPT = Pattern.compile("(\\w+\\['\\w+'\\])");
    protected static Pattern arrayIndexPT = Pattern.compile("(\\w+\\[\\d+\\])");

    /**
     * 根据获取输入的值
     *
     * @param node
     * @param context
     * @return
     */
    public Object getInputObject(TNode node, TemplateContext context)
    {

        Object val = null;
        if (node != null && node.getInputKey() != null)
        {
            if (node.parentNode != null && node.getInputKey().equalsIgnoreCase(node.parentNode.getOutKey()))

            {
                val = node.parentNode.getOutValue();
            }
            else
            {
                val = context.getObject(node.getInputKey());
            }
        }
        return val;
    }

    /**
     * 递归调用反射出表达式的值
     * @param instance
     * @param attributes
     * @param index
     * @return
     * @throws Exception
     */
    public Object invokeMethod(Object instance, String[] attributes, int
            index) throws Exception
    {
        Object retValue = instance;
        if(index < attributes.length){
            retValue = ClassUtil.invokeMethod(instance,
                    StringUtil.getGetMethodNameWithAttribute(attributes[index]), null);
            retValue = invokeMethod(retValue, attributes, index + 1);
        }
        return retValue;
    }

    /**
     * 获取实际的值
     * @param key
     * @param input
     * @return
     */
    public Object getInputObject(String key, Object input){
        if(!StringUtil.isEmpty(key)){
            Matcher m = mapKeyPT.matcher(key);
            if(m.find()){
                if(input instanceof Map){
                    String realKey = key;
                    realKey = realKey.substring(m.start(), m.end()).replaceAll("'\\]", "");
                    String[] splitKeys = realKey.split("\\['");
                    if(splitKeys.length > 1){
                        return ((Map) input).get(splitKeys[1]);
                    }else{
                        throw new TemplateException(Errors.syntax_error, key);
                    }
                }else{
                    throw new TemplateException(Errors.express_value_type_not_match,
                            key+":"+ input.getClass());
                }
            }
            m = arrayIndexPT.matcher(key);
            if(m.find()){
                String index = key;
                index = index.substring(m.start(), m.end()).replaceAll("\\]", "");
                String[] splitKeys = index.split("\\[");
                int size = 0;
                int arrayIndex = 0;
                if(input instanceof Object[]){
                    if(splitKeys.length > 1){
                        size = ((Object[])input).length;
                        arrayIndex = Integer.parseInt(splitKeys[1]);
                        if(arrayIndex >= size){
                            throw new TemplateException(Errors.index_out_of_bounds,
                                    "Index:"+arrayIndex + ", Size:" +size);
                        }
                        return ((Object[])input)[Integer.parseInt(splitKeys[1])];
                    }else{
                        throw new TemplateException(Errors.syntax_error, key);
                    }
                }else if(input instanceof List){
                    if(splitKeys.length > 1){
                        size = ((List) input).size();
                        arrayIndex = Integer.parseInt(splitKeys[1]);
                        if(arrayIndex >= size){
                            throw new TemplateException(Errors.index_out_of_bounds,
                                    "Index:"+arrayIndex + ", Size:" +size);
                        }
                        return ((List)input).get(arrayIndex);
                    }else{
                        throw new TemplateException(Errors.syntax_error, key);
                    }
                }else{
                    throw new TemplateException(Errors.express_value_type_not_match,
                            key+":"+ input.getClass());
                }
            }
        }
        return input;
    }

    /**
     * 根据属性列表、输入值和inputKey获得表达式的值
     * @param attributes
     * @param inputObj
     * @param inputKey
     * @param ex
     * @return
     * @throws Exception
     */
    protected Object getObjectWithAttrsAndInputObj(String[] attributes, Object inputObj, String
            inputKey, String ex)
            throws
            Exception
    {
        Object retObj = null;
        if(attributes.length == 1){
            retObj = getInputObject(attributes[0], inputObj);
            if(retObj == null && attributes[0].equalsIgnoreCase(inputKey)){
                retObj = inputObj;
            }
        }else if(attributes.length > 1){
            for (int i=1; i<attributes.length; i++){
                if(StringUtil.isEmpty(attributes[i])){
                    throw new TemplateException(Errors.syntax_error, ex);
                }
            }
            inputObj = getInputObject(attributes[0], inputObj);
            retObj = invokeMethod(inputObj, attributes, 1);
        }
        return retObj;
    }
}